#include "mainwindow.h"
#include "ui_mainwindow.h"
#include<QHostAddress>
#include<QMessageBox>
//#include "tunkia.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    已连接=false;
    不让重复发=0;
    //要注册QList<int>，才能跨线程发送List类型
    qRegisterMetaType<QList<int>>("QList<int>");

/**↓↓↓↓↓↓↓↓↓↓↓↓↓↓默认是使用TD3650↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓**/
    ui->radioB_3650->setChecked(true);
    ui->combo_4550->hide();
    ui->label_4550->hide();
    ui->label_IP->show();
    ui->lineE_IP->show();
    ui->label_IPport->show();
    ui->lineE_IPport->show();
/**↑↑↑↑↑↑↑↑↑↑↑↑↑默认是使用TD3650↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑**/

    查找可用的串口(ui->combo_4550);

/**↓↓↓↓↓↓↓↓↓↓↓↓↓↓开启校准可能会用到的5个子线程↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓**/
    thread_4550 = new QThread;//Qt中的线程类，这里用作子线程
    SerialTh_4550 = new TD4550SerialThread;//串口线程
    SerialTh_4550->moveToThread(thread_4550);

    thread_NO1 = new QThread;//Qt中的线程类，这里用作子线程
    SerialTh_NO1 = new SerialThread;//串口线程
    SerialTh_NO1->moveToThread(thread_NO1);

    thread_NO2 = new QThread;//Qt中的线程类，这里用作子线程
    SerialTh_NO2 = new SerialThread;//串口线程
    SerialTh_NO2->moveToThread(thread_NO2);

    thread_NO3 = new QThread;//Qt中的线程类，这里用作子线程
    SerialTh_NO3 = new SerialThread;//串口线程
    SerialTh_NO3->moveToThread(thread_NO3);

    thread_3650 = new QThread;//Qt中的线程类，这里用作子线程
    ClientTh_3650 = new TD3650ClientThread;
    ClientTh_3650->moveToThread(thread_3650);

    thread_4550->start();
    thread_NO1->start();
    thread_NO2->start();
    thread_NO3->start();
    thread_3650->start();
/**↑↑↑↑↑↑↑↑↑↑↑↑↑开启校准可能会用到的5个子线程↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑**/

//    timer步骤 = new QTimer(this);
//    QObject::connect(timer步骤,&QTimer::timeout,this,[=](){MainWindow::_校准步骤分发();});

    connect(this,&MainWindow::_校准步骤分发信号,this,&MainWindow::_校准步骤分发,Qt::QueuedConnection);//用来更新线程的状态

    ui->lineE_IP->setText("192.168.11.35");
    ui->lineE_IPport->setText("8000");



    qDebug()<<"主线程是"<<QThread::currentThread();

}

MainWindow::~MainWindow()
{
    delete ui;
}



void MainWindow::on_radioB_4550_clicked(bool checked)
{
    if(checked)
    {
        ui->combo_4550->clear();
        查找可用的串口(ui->combo_4550);
        qDebug()<<"4550已选中"<<checked;

        ui->radioB_3650->setChecked(false);

        ui->combo_4550->show();
        ui->label_4550->show();

        ui->label_IP->hide();
        ui->lineE_IP->hide();
        ui->label_IPport->hide();
        ui->lineE_IPport->hide();
    }
}


void MainWindow::on_radioB_3650_clicked(bool checked)
{
    if(checked)
    {
        qDebug()<<"3560已选中"<<checked;
        ui->radioB_4550->setChecked(false);
        ui->combo_4550->hide();
        ui->label_4550->hide();

        ui->label_IP->show();
        ui->lineE_IP->show();
        ui->label_IPport->show();
        ui->lineE_IPport->show();
    }
}


//开始校准按键, 首先检查用了哪个仪器, 再确定使用的工位型号和串口
void MainWindow::on_pButt_startC_clicked()
{
    ui->textE_receiver_0->clear();
    ui->textE_receiver_1->clear();
    ui->textE_receiver_2->clear();
    ui->textE_receiver_3->clear();

    工位状态[0]=0;
    工位状态[1]=0;
    工位状态[2]=0;
    //工位状态[3]={0,0,0};//类中定义的数组无法如此初始化/赋值

/**↓↓↓↓↓↓↓↓↓↓↓↓↓↓界面的检查↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓**/
    if(ui->checkBox_NO1->isChecked()) 工位状态[0]=1;
    if(ui->checkBox_NO2->isChecked()) 工位状态[1]=1;
    if(ui->checkBox_NO3->isChecked()) 工位状态[2]=1;
    int 打开工位个数=工位状态[0]+工位状态[1]+工位状态[2];

    //使用TD4550, 只能使用一个工位
    if(ui->radioB_4550->isChecked())
    {
         qDebug()<<"4550选中";

         if(打开工位个数 == 0) {QMessageBox::information(this,"注意!!!","工位未选择"); return; }
         if(打开工位个数 >  1) {QMessageBox::information(this,"注意!!!","只能选择一个工位");return; }
         if(打开工位个数 ==  1){qDebug()<<"选择了一个工位";}
    }

    //使用TD3650, 可使用多个工位
    if(ui->radioB_3650->isChecked())
    {
         qDebug()<<"3650选中";
         if(打开工位个数 == 0) {QMessageBox::information(this,"注意!!!","工位未选择"); return; }
         else qDebug()<<"打开工位个数"<<打开工位个数;
    }

    //检查型号是否已选择, 以及串口是否有重复选择
    bool 检查结果=检查型号及串口();
    if(!检查结果){return;}//型号未选择或串口有重复则不执行校准
/**↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑界面的检查↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑**/

    ui->pButt_startC->setEnabled(false);
    ui->pButt_startC->setText("正在校准");
/***********确定选择没有问题了,下面开始仪器和样机的检查************/

/**↓↓↓↓↓↓↓↓↓↓↓↓↓↓使用TD4550校准↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓**/
    if(ui->radioB_4550->isChecked())
    {
        QString 塑壳串口;
        QString 塑壳型号;

        if(工位状态[0])
            {塑壳串口=ui->combo_NO1->currentText(); 塑壳型号=ui->combo_type1->currentText();}
        if(工位状态[1])
            {塑壳串口=ui->combo_NO2->currentText(); 塑壳型号=ui->combo_type2->currentText();}
        if(工位状态[2])
            {塑壳串口=ui->combo_NO3->currentText(); 塑壳型号=ui->combo_type3->currentText();}

        使用TD4550校准(ui->combo_4550->currentText(),塑壳串口,塑壳型号);
    }
/**↑↑↑↑↑↑↑↑↑↑↑↑↑↑使用TD4550校准↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑**/

/**↓↓↓↓↓↓↓↓↓↓↓↓↓↓使用TD3650校准↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓**/
    if(ui->radioB_3650->isChecked())
    {
        bool ok;

        使用TD3650校准(ui->lineE_IP->text(),ui->lineE_IPport->text().toUInt(&ok,10));
        qDebug()<<"3650选中IP"<<ui->lineE_IP->text();
        qDebug()<<"3650选中IP端口"<<ui->lineE_IPport->text().toUInt(&ok,10);
    }
/**↑↑↑↑↑↑↑↑↑↑↑↑↑↑使用TD3640校准↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑**/
}

//调用此函数前就检查过工位个数了, 所以可以简化此函数
//检查型号是否已选择, 以及串口是否有重复选择
bool MainWindow::检查型号及串口()
{
    bool 检查结果=true;

    if(工位状态[0])
    {
        if(ui->radioB_4550->isChecked())
        {
            if(ui->combo_4550->currentText()==ui->combo_NO1->currentText()) 检查结果=false;
            if(!检查结果)
            {  QMessageBox::warning(this,"错误提示","与TD4550的串口号重复") ;return 检查结果;}
        }
        if(ui->combo_type1->currentIndex()==0)
        {   QMessageBox::warning(this,"错误提示","1号工位未选型号") ;检查结果=false; return 检查结果;}

        if(ui->combo_NO1->currentText()==ui->combo_NO2->currentText()) 检查结果=false;
        if(ui->combo_NO1->currentText()==ui->combo_NO3->currentText()) 检查结果=false;
        //if(ui->combo_NO2->currentText()==ui->combo_NO3->currentText()) 检查结果=false;
        if(!检查结果)
        {   QMessageBox::warning(this,"错误提示","产品串口号重复") ;return 检查结果;}


    }

    if(工位状态[1])
    {
        if(ui->radioB_4550->isChecked())
        {
            if(ui->combo_4550->currentText()==ui->combo_NO2->currentText()) 检查结果=false;
            if(!检查结果)
            {  QMessageBox::warning(this,"错误提示","与TD4550的串口号重复") ;return 检查结果;}
        }
        if(ui->combo_type2->currentIndex()==0)
        {   QMessageBox::warning(this,"错误提示","2号工位未选型号") ;检查结果=false; return 检查结果;}

        if(ui->combo_NO1->currentText()==ui->combo_NO2->currentText()) 检查结果=false;
        //if(ui->combo_NO1->currentText()==ui->combo_NO3->currentText()) 检查结果=false;
        if(ui->combo_NO2->currentText()==ui->combo_NO3->currentText()) 检查结果=false;
        if(!检查结果)
        {   QMessageBox::warning(this,"错误提示","产品串口号重复") ;return 检查结果;}
    }

    if(工位状态[2])
    {
        if(ui->radioB_4550->isChecked())
        {
            if(ui->combo_4550->currentText()==ui->combo_NO3->currentText()) 检查结果=false;
            if(!检查结果)
            {  QMessageBox::warning(this,"错误提示","与TD4550的串口号重复") ;return 检查结果;}
        }
        if(ui->combo_type3->currentIndex()==0)
        {   QMessageBox::warning(this,"错误提示","3号工位未选型号") ;检查结果=false; return 检查结果;}

        //if(ui->combo_NO1->currentText()==ui->combo_NO2->currentText()) 检查结果=false;
        if(ui->combo_NO1->currentText()==ui->combo_NO3->currentText()) 检查结果=false;
        if(ui->combo_NO2->currentText()==ui->combo_NO3->currentText()) 检查结果=false;
        if(!检查结果)
        {   QMessageBox::warning(this,"错误提示","产品串口号重复") ;return 检查结果;}
    }

    return 检查结果;
}

void MainWindow::使用TD4550校准(QString 仪器串口,QString 塑壳串口,QString 塑壳型号)
{

/**↓↓↓↓↓↓↓↓↓↓↓↓↓配置TD4550↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓**/
    connect(this,&MainWindow::sendConj4550,SerialTh_4550,&TD4550SerialThread::getConj,Qt::QueuedConnection);//串口配置,
    connect(this,&MainWindow::calibrate_TD4550,SerialTh_4550,&TD4550SerialThread::calibrate_TD4550,Qt::QueuedConnection);//同步校准步骤
    QList<int> comConj;
    comConj<<7<<0<<0<<3<<0;
    emit sendConj4550(仪器串口,comConj);//TD4550线程会在得到配置后打开串口

    connect(SerialTh_4550,&TD4550SerialThread::TD4550State,this,&MainWindow::TD4550State,Qt::QueuedConnection);//用来更新线程的状态
/**↑↑↑↑↑↑↑↑↑↑↑配置TD4550↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑**/


/**↓↓↓↓↓↓↓↓↓↓↓↓↓配置校准样机↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓**/
    connect(this,&MainWindow::sendConj_NO1,SerialTh_NO1,&SerialThread::getConj);//串口配置,
    QList<int> comConj_NO;
    comConj_NO<<4<<0<<0<<3<<0;
    emit sendConj_NO1(塑壳串口,塑壳型号,comConj_NO,1);//样机线程会在得到配置后打开串口
    connect(this,&MainWindow::calibrate_NO1,SerialTh_NO1,&SerialThread::calibrate_simple,Qt::QueuedConnection);//同步校准步骤
    connect(SerialTh_NO1,&SerialThread::SimpleState,this,&MainWindow::SimpleState_1,Qt::QueuedConnection);//用来更新线程的状态
/**↑↑↑↑↑↑↑↑↑配置校准样机↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑**/

    //开启线程表 用来比较,  校准步骤表 用来更新状态
    使用的源=45;//这是表明用的是那个源,只应在此被赋值,后面也不应被修改
    开启线程表[0]=1;//源的线程, 后续不应被更改,后续只有被停止校准才赋为0
    开启线程表[1]=1;//样机1的线程, 后续不应被更改,后续只有被停止校准才赋为0
    开启线程表[2]=0;//样机1的线程
    开启线程表[3]=0;//样机1的线程

    校准步骤表[0]=0;//这是源的状态
    校准步骤表[1]=0;//这是样机1的状态, 当用TD4550校准,样机只开线程1, 在其它地方只应增加, 不应写为0
    校准步骤表[2]=0;//这是样机2的状态//只能这里写为0,在其它地方不应写成0,
    校准步骤表[3]=0;//这是样机3的状态
    不让重复发=0;

    //真正开始校准
   // timer步骤->start(2000);
    校准步骤=1;
}


void MainWindow::使用TD3650校准(QString IP地址,int IP端口)
{

/**↓↓↓↓↓↓↓↓↓↓↓↓↓配置TD3650↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓**/
    connect(this,&MainWindow::sendConj3650,ClientTh_3650,&TD3650ClientThread::getConj,Qt::QueuedConnection);//网口
    connect(this,&MainWindow::calibrate_TD3650,ClientTh_3650,&TD3650ClientThread::calibrate_TD3650,Qt::QueuedConnection);//同步校准步骤
    emit sendConj3650(IP地址,IP端口);//TD3650线程会在得到配置后连接服务器

    connect(ClientTh_3650,&TD3650ClientThread::TD3650State,this,&MainWindow::TD3650State,Qt::QueuedConnection);//出现错误, 用来停止线程
    使用的源=36;//这是表明用的是那个源,只应在此被赋值,后面也不应被修改
    开启线程表[0]=1;
    开启线程表[1]=0;//样机状态初始化先设为0,后面根据工位状态,再写入对应的值
    开启线程表[2]=0;
    开启线程表[3]=0;

    校准步骤表[0]=0;//这是源的状态
    校准步骤表[1]=0;
    校准步骤表[2]=0;
    校准步骤表[3]=0;
    不让重复发=0;
/**↑↑↑↑↑↑↑↑↑↑↑配置TD3650↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑**/

/**↓↓↓↓↓↓↓↓↓↓↓↓↓配置校准样机↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓**/
    QString 塑壳串口;
    QString 塑壳型号;
    QList<int> comConj_NO;
    comConj_NO<<4<<0<<0<<3<<0;

    if(工位状态[0])
    {
        塑壳串口=ui->combo_NO1->currentText(); 塑壳型号=ui->combo_type1->currentText();

        connect(this,&MainWindow::sendConj_NO1,SerialTh_NO1,&SerialThread::getConj,Qt::QueuedConnection);//串口配置,
        QList<int> comConj_NO;
        comConj_NO<<4<<0<<0<<3<<0;
        emit sendConj_NO1(塑壳串口,塑壳型号,comConj_NO,1);//样机线程会在得到配置后打开串口
        connect(this,&MainWindow::calibrate_NO1,SerialTh_NO1,&SerialThread::calibrate_simple,Qt::QueuedConnection);//同步校准步骤
        connect(SerialTh_NO1,&SerialThread::SimpleState,this,&MainWindow::SimpleState_1,Qt::QueuedConnection);//用来更新线程的状态
        开启线程表[1]=1;

    }

    if(工位状态[1])
    {
        塑壳串口=ui->combo_NO2->currentText(); 塑壳型号=ui->combo_type2->currentText();

        connect(this,&MainWindow::sendConj_NO2,SerialTh_NO2,&SerialThread::getConj,Qt::QueuedConnection);//串口配置,
        QList<int> comConj_NO;
        comConj_NO<<4<<0<<0<<3<<0;
        emit sendConj_NO2(塑壳串口,塑壳型号,comConj_NO,2);//样机线程会在得到配置后打开串口
        connect(this,&MainWindow::calibrate_NO2,SerialTh_NO2,&SerialThread::calibrate_simple,Qt::QueuedConnection);//同步校准步骤
        connect(SerialTh_NO2,&SerialThread::SimpleState,this,&MainWindow::SimpleState_2,Qt::QueuedConnection);//用来更新线程的状态
        开启线程表[2]=1;
    }

    if(工位状态[2])
    {
        塑壳串口=ui->combo_NO3->currentText(); 塑壳型号=ui->combo_type3->currentText();

        connect(this,&MainWindow::sendConj_NO3,SerialTh_NO3,&SerialThread::getConj,Qt::QueuedConnection);//串口配置,
        QList<int> comConj_NO;
        comConj_NO<<4<<0<<0<<3<<0;
        emit sendConj_NO3(塑壳串口,塑壳型号,comConj_NO,3);//样机线程会在得到配置后打开串口
        connect(this,&MainWindow::calibrate_NO3,SerialTh_NO3,&SerialThread::calibrate_simple,Qt::QueuedConnection);//同步校准步骤
        connect(SerialTh_NO3,&SerialThread::SimpleState,this,&MainWindow::SimpleState_3,Qt::QueuedConnection);//用来更新线程的状态
        开启线程表[3]=1;
    }
/**↑↑↑↑↑↑↑↑↑↑↑配置校准样机↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑**/

    //真正开始校准
    //timer步骤->start(3000);
    校准步骤=1;

}


//每500mS检查一次
void MainWindow::_校准步骤分发()
{
    qDebug()<<"线程状态"<<开启线程表[0]<<开启线程表[1]<<开启线程表[2]<<开启线程表[3];
    qDebug()<<"步骤状态"<<校准步骤表[0]<<校准步骤表[1]<<校准步骤表[2]<<校准步骤表[3];
    qDebug()<<"目前校准步骤"<<校准步骤;
/**↓↓↓↓↓↓↓↓↓↓如果是源出了问题, 关闭全部校准↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓**/
    //
   // if(0==开启线程表[0]+开启线程表[1]+开启线程表[2]+开启线程表[3]){ return;}
    if(校准步骤==0){ return;}
    if(!开启线程表[0])
    {
       // timer步骤->stop();
        校准步骤=0;
        if(使用的源==45) {emit calibrate_TD4550(101); }//步骤100, 定义为停止校准, 关闭连接
        if(使用的源==36) {emit calibrate_TD3650(101); }//步骤100, 定义为停止校准, 关闭连接
        if(开启线程表[1]) {emit calibrate_NO1(101); 开启线程表[1]=0;}//步骤100, 定义为停止校准, 如果样机还没停止,也要关闭与样机的连接
        if(开启线程表[2]) {emit calibrate_NO2(101); 开启线程表[2]=0;}
        if(开启线程表[3]) {emit calibrate_NO3(101); 开启线程表[3]=0;}
        return;
    }

/**↑↑↑↑↑↑↑↑↑↑如果是源出了问题, 关闭全部校准↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑**/

    /***********要确保不要关闭两次串口或网络***************/

/**↓↓↓↓↓↓↓↓↓↓如果是样机出了问题, 关闭对应的样机校准↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓**/
    if(校准步骤表[1] && !开启线程表[1]) {emit calibrate_NO1(101); }//qDebug()<<"步骤状态关闭样机1"<<校准步骤表[1]<<开启线程表[1];}//如果步骤值不等于0, 并且对应的 开启线程表为0, 则执行此条; 以停止样机1的校准
    if(校准步骤表[2] && !开启线程表[2]) {emit calibrate_NO2(101); }//qDebug()<<"步骤状态关闭样机2"<<校准步骤表[2]<<开启线程表[2];}
    if(校准步骤表[3] && !开启线程表[3]) {emit calibrate_NO3(101); }//qDebug()<<"步骤状态关闭样机3"<<校准步骤表[3]<<开启线程表[3];}


    int j=0;
    for(int i=1;i<=3;i++) {j+=开启线程表[i];}
    //3个校准线程均为0,表示所有样机已校完成, 或停止运行
    qDebug()<<"目前样机个数"<<j;
    if(j==0)
    {
      //  timer步骤->stop();
        if(使用的源==45 && 开启线程表[0]) emit calibrate_TD4550(101);//步骤100, 定义为停止校准, 关闭连接, 当源的线程表[0]还为1才执行, 否则前面也执行了1次,这次又执行
        if(使用的源==36 && 开启线程表[0]) emit calibrate_TD3650(101);//步骤100, 定义为停止校准, 关闭连接, 当源的线程表[0]还为1才执行, 否则前面也执行了1次,这次又执行
        ui->pButt_startC->setEnabled(true);
        return;
    }

/**↑↑↑↑↑↑↑↑↑↑如果是样机出了问题, 关闭对应的样机校准↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑**/

//校准步骤从1开始,校准步骤表各元素也是从1开始.
//校准步骤表[0]返回2, 表明通讯正常,三相电压220V,电流0A. 源的步骤2是已完成了.  校准步骤变为2, 样机开始的执行步骤2,即检测样机能否通讯, 确认可以开始校准的工位, 以及开始写入数据, 校零点电流
//等样机返回的校准步骤表都变为2, 源开始执行校准步骤3.
//校准步骤表[0]返回3, 表明源已经准备好了,校准步骤变为4, 样机开始的执行步骤3.
//等样机返回的校准步骤表都变为3, 源开始执行校准步骤4.


    //条件成立, 表示源的步骤已完成, 可以开始样机的同一步骤, 不成立就等下一次检测
    if(校准步骤表[0]==校准步骤 && 校准步骤> 不让重复发)
    {
        qDebug()<<"样机开始校准步骤"<<校准步骤;
        if(开启线程表[1]) emit calibrate_NO1(校准步骤);
        if(开启线程表[2]) emit calibrate_NO2(校准步骤);
        if(开启线程表[3]) emit calibrate_NO3(校准步骤);
        //校准步骤++;//校准步骤++放这是为了一个步骤只执行一次这个if函数

        不让重复发=校准步骤;
    }
    qDebug()<<"当前校准步骤"<<校准步骤;

    int 已校准数=0;
    if(开启线程表[1])//检查线程是否已开, 和检查校准步骤表没有更新加1
    {
        if(校准步骤表[1]==校准步骤) 已校准数++;// 因为前面执行了 校准步骤++, 所以校准步骤-1 才是当前要执行的步骤
    }
    if(开启线程表[2])
    {
        if(校准步骤表[2]==校准步骤) 已校准数++;
    }
    if(开启线程表[3])
    {
        if(校准步骤表[3]==校准步骤) 已校准数++;
    }

    int 在校工位数=0;
    for(int i=0;i<3;i++)//得到在校准的样机还有多少个
    {
        在校工位数+=开启线程表[i+1];
    }

    qDebug()<<"在校工位数"<<在校工位数;


    //所有样机都校准了, 则可以开启下一段校准
    if(开启线程表[0] && 在校工位数!=0 && 已校准数==在校工位数)
    {
        校准步骤++;//校准步骤++放这是为了一个步骤只执行一次这个if函数

        qDebug()<<"源开始校准步骤"<<校准步骤;

        if(使用的源==45) emit calibrate_TD4550(校准步骤);
        if(使用的源==36) emit calibrate_TD3650(校准步骤);
    }


}



void MainWindow::TD4550State(QString 错误信息,bool 错误码, int 状态码)
{
    ui->textE_receiver_0->append(错误信息);
    校准步骤表[0]=状态码;


    if(!错误码)
    {
        开启线程表[0]=0;//在错误码为true时, 忽略状态码, 只将开启线程表赋为0, 以停止子线程
        //QMessageBox::information(this,"问题",错误信息);
        if(状态码==100)//这个100码是校准过程出错，TD源主动返回的。
        {
           // ui->pButt_startC->setEnabled(true);
        }
        if(状态码==101)//这个101码, 是接收到100码后，由主线程发送101码，再由TD子线程返回101码，确认已关闭子线程
        {
            sleepMsec(500);
            ui->pButt_startC->setEnabled(true);
            ui->pButt_startC->setText("开始校准");
            disconnect(this,&MainWindow::sendConj4550,SerialTh_4550,&TD4550SerialThread::getConj);//串口配置,
            disconnect(this,&MainWindow::calibrate_TD4550,SerialTh_4550,&TD4550SerialThread::calibrate_TD4550);//同步校准步骤
            disconnect(SerialTh_4550,&TD4550SerialThread::TD4550State,this,&MainWindow::TD4550State);//用来更新线程的状态
            return;
        }

    }
    emit _校准步骤分发信号();



}

void MainWindow::TD3650State(QString 错误信息,bool 错误码, int 状态码)
{
    ui->textE_receiver_0->append(错误信息);
    校准步骤表[0]=状态码;

    if(!错误码)
    {
        开启线程表[0]=0;//在错误码为true时, 忽略状态码, 只将开启线程表赋为0, 以停止子线程
        //QMessageBox::information(this,"问题",错误信息);
        if(状态码==100)//返回状态码等于100,表示网口已关闭
        {
            //ui->pButt_startC->setEnabled(true);
        }
        if(状态码==101)//这个101码, 是接收到100码后，由主线程发送101码，再由TD子线程返回101码，确认已关闭子线程
        {
            sleepMsec(500);
            ui->pButt_startC->setEnabled(true);
            ui->pButt_startC->setText("开始校准");
            disconnect(this,&MainWindow::sendConj3650,ClientTh_3650,&TD3650ClientThread::getConj);//网口
            disconnect(this,&MainWindow::calibrate_TD3650,ClientTh_3650,&TD3650ClientThread::calibrate_TD3650);//同步校准步骤
            disconnect(ClientTh_3650,&TD3650ClientThread::TD3650State,this,&MainWindow::TD3650State);//出现错误, 用来停止线程
            return;
        }

    }
    if(!状态码) return;

    emit _校准步骤分发信号();

}

void MainWindow::SimpleState_1(QString 错误信息,bool 错误码, int 状态码)
{
    ui->textE_receiver_1->append(错误信息);

    qDebug()<<"样机1的其它错误码"<<状态码;
    if(!错误码)
    {
        //开启线程表[1]=0;//将开启线程表赋为0, 以停止子线程//此语句必须放到disconnect语言前面, 否则不执行
       // QMessageBox::information(this,"问题",错误信息);
        if(状态码==100)
        {
            开启线程表[0]=0;//设为0停止源就要停止全部线程
        }
        else if(状态码==101)
        {
            开启线程表[1]=0;
            sleepMsec(100);
            disconnect(this,&MainWindow::sendConj_NO1,SerialTh_NO1,&SerialThread::getConj);//串口配置,
            disconnect(this,&MainWindow::calibrate_NO1,SerialTh_NO1,&SerialThread::calibrate_simple);//同步校准步骤
            disconnect(SerialTh_NO1,&SerialThread::SimpleState,this,&MainWindow::SimpleState_1);//取消与本函数的关联
            //return;
        }
        else//其它错误码，只停止自己
        {
             开启线程表[1]=0;
             emit calibrate_NO1(101);
             return;//此步后先退出，后面会返回101状态码时，才会关闭子线程序
        }
    }

    校准步骤表[1]=状态码;
    emit _校准步骤分发信号();

}

void MainWindow::SimpleState_2(QString 错误信息,bool 错误码, int 状态码)
{
    ui->textE_receiver_2->append(错误信息);



    if(!错误码)
    {
        //开启线程表[2]=0;//将开启线程表赋为0, 以停止子线程//此语句必须放到disconnect语言前面, 否则不执行
        //QMessageBox::information(this,"问题",错误信息);
        if(状态码==100)//100是最严重的异常，会关闭源，其它小于100的状态码则只停止样机线程
        {
            //emit calibrate_NO2(101);
            开启线程表[0]=0;//设为0停止源就要停止全部线程
        }
        else if(状态码==101)
        {
            开启线程表[2]=0;
            sleepMsec(100);
            disconnect(this,&MainWindow::sendConj_NO2,SerialTh_NO2,&SerialThread::getConj);//串口配置,
            disconnect(this,&MainWindow::calibrate_NO2,SerialTh_NO2,&SerialThread::calibrate_simple);//同步校准步骤
            disconnect(SerialTh_NO2,&SerialThread::SimpleState,this,&MainWindow::SimpleState_2);//取消与本函数的关联
        }
        else//其它错误码，只停止自己
        {
              开启线程表[2]=0;
              emit calibrate_NO2(101);
              return;//此步后先退出，后面会返回101状态码时，才会关闭子线程序
        }
    }
    校准步骤表[2]=状态码;
    emit _校准步骤分发信号();

}

void MainWindow::SimpleState_3(QString 错误信息,bool 错误码, int 状态码)
{
    ui->textE_receiver_3->append(错误信息);

    if(!错误码)
    {
        //开启线程表[3]=0;//将开启线程表赋为0, 以停止子线程//此语句必须放到disconnect语言前面, 否则不执行
        //QMessageBox::information(this,"问题",错误信息);
        if(状态码==100)
        {
           // emit calibrate_NO3(101);
            开启线程表[0]=0;//设为0停止源就要停止全部线程
        }
        else if(状态码==101)
        {
            开启线程表[3]=0;
            sleepMsec(100);
            disconnect(this,&MainWindow::sendConj_NO3,SerialTh_NO3,&SerialThread::getConj);//串口配置,
            disconnect(this,&MainWindow::calibrate_NO3,SerialTh_NO3,&SerialThread::calibrate_simple);//同步校准步骤
            disconnect(SerialTh_NO3,&SerialThread::SimpleState,this,&MainWindow::SimpleState_3);//取消与本函数的关联
        }
        else//其它错误码，只停止自己
        {
            开启线程表[3]=0;
            emit calibrate_NO3(101);
            return;//此步后先退出，后面会返回101状态码时，才会关闭子线程序
        }
    }

    校准步骤表[3]=状态码;
    emit _校准步骤分发信号();

}





//工位1可选125   400  630 三种型号
void MainWindow::on_checkBox_NO1_clicked(bool checked)
{
   // qDebug()<<"NO1选择状态"<<checked;
    if(checked)
    {
    QMessageBox *msgBox = new QMessageBox(QMessageBox::Question,tr("工位1选择型号"),
                                          QString(tr("工位1 要校准的是什么型号?")),
                                          QMessageBox::Yes | QMessageBox::No| QMessageBox::Cancel);

           msgBox->button(QMessageBox::Yes)->setText("EL125");
           msgBox->button(QMessageBox::No)->setText("EL400");
           msgBox->button(QMessageBox::Cancel)->setText("EL630");
    int value = msgBox->exec();

    if(value==QMessageBox::Yes) ui->combo_type1->setCurrentIndex(1);//EL125
    if(value==QMessageBox::No ) ui->combo_type1->setCurrentIndex(2);//EL400
    if(value==QMessageBox::Cancel) ui->combo_type1->setCurrentIndex(3);//EL630

    查找可用的串口(ui->combo_NO1);

    }

    else {//清空下拉框的信息
        ui->combo_type1->setCurrentIndex(0);
        ui->combo_NO1->clear();
    }

}

//工位2可选125   250 两种型号
void MainWindow::on_checkBox_NO2_clicked(bool checked)
{
    if(checked)
    {
    QMessageBox *msgBox = new QMessageBox(QMessageBox::Question,tr("工位2选择型号"),
                                          QString(tr("工位2 要校准的是什么型号?")),
                                          QMessageBox::Yes | QMessageBox::No);

           msgBox->button(QMessageBox::Yes)->setText("EL125");
           msgBox->button(QMessageBox::No)->setText("EL250");
    int value = msgBox->exec();

    if(value==QMessageBox::Yes) ui->combo_type2->setCurrentIndex(1);//EL125
    if(value==QMessageBox::No ) ui->combo_type2->setCurrentIndex(2);//EL250

    查找可用的串口(ui->combo_NO2);

    }

    else {//清空下拉框的信息
        ui->combo_type2->setCurrentIndex(0);
        ui->combo_NO2->clear();
    }
}

//工位3可选125   250 两种型号
void MainWindow::on_checkBox_NO3_clicked(bool checked)
{   
    if(checked)
    {
    QMessageBox *msgBox = new QMessageBox(QMessageBox::Question,tr("工位3选择型号"),
                                          QString(tr("工位3 要校准的是什么型号?")),
                                          QMessageBox::Yes | QMessageBox::No);

           msgBox->button(QMessageBox::Yes)->setText("EL125");
           msgBox->button(QMessageBox::No)->setText("EL250");
    int value = msgBox->exec();    

    if(value==QMessageBox::Yes) ui->combo_type3->setCurrentIndex(1);//EL125
    if(value==QMessageBox::No ) ui->combo_type3->setCurrentIndex(2);//EL250

    查找可用的串口(ui->combo_NO3);

    }

    else {//清空下拉框的信息
        ui->combo_type3->setCurrentIndex(0);
        ui->combo_NO3->clear();
    }
}

void MainWindow::查找可用的串口(QComboBox *下拉框)
{
    /*********查找可用的串口*******************-start-**/
        foreach (const QSerialPortInfo &info,QSerialPortInfo::availablePorts())
        {
            QSerialPort FindSerial;
            FindSerial.setPort(info);
            if(FindSerial.open(QIODevice::ReadWrite))
            {
                下拉框->addItem(FindSerial.portName());
                FindSerial.close();
            }
        }
    /******************************************-end-**/

}
